package io.gitee.caoxiaoyu97.messageconvert.client.customer;

import freemarker.template.TemplateException;
import io.gitee.caoxiaoyu97.messageconvert.client.CxyCloudAdapterClientUtil;
import io.gitee.caoxiaoyu97.messageconvert.client.codeconvert.CxyCloudAdapterInCodeConvert;
import io.gitee.caoxiaoyu97.messageconvert.client.ext.CxyCloudAdapterConvertProcessor;
import io.gitee.caoxiaoyu97.messageconvert.common.CxyCloudTemplateUtils;
import io.gitee.caoxiaoyu97.messageconvert.exception.CxyException;
import io.gitee.caoxiaoyu97.messageconvert.util.MessageUtils;
import io.gitee.caoxiaoyu97.util.StrFormatUtils;

import java.io.IOException;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/*********************************************************
 * 文件名称：CxyCloudAdapterServiceUtil.java
 * 系统名称：cxycloud
 * 模块名称：io.gitee.caoxiaoyu97.messageconvert.client.ext
 * 功能说明：适配器服务工具
 * 开发人员 @author：caoxy
 * 开发时间 @date：2023/7/19 15:01
 * 修改记录：程序版本  修改日期  修改人员  修改单号  修改说明
 *********************************************************/
public class CxyCloudAdapterServiceUtil {


    public static String invokeService(String inCode, String req) {
        CxyCloudAdapterCustomerMetadata adapterCustomerMetadata =
                CxyCloudAdapterClientUtil.getAdapterCustomerMetadata(inCode);
        String inCodeConvertBeanName = adapterCustomerMetadata.getInCodeConvertBeanName();
        CxyCloudAdapterInCodeConvert adapterCodeConvert =
                CxyCloudAdapterClientUtil.getAdapterCodeConvert(inCodeConvertBeanName);
        String convertCode = adapterCodeConvert.convert(inCode, req,MessageUtils.messageToMap(req));
        CxyCloudAdapterConvertMetadata convertMetadata =
                adapterCustomerMetadata.getConvertMetadataMap().get(convertCode);
        if (convertMetadata == null){
            throw new CxyException("9999", StrFormatUtils.formatMessage("[{}]服务根据内部交易码[{}]获得的外部交易码[{}]在配置中不存在",
                    inCodeConvertBeanName,inCode,convertCode));
        }
        try {
            return invokeServiceHandle(convertMetadata, req);
        } catch (TemplateException e) {
            throw new CxyException("9900", "模板渲染异常", e);
        } catch (IOException e) {
            throw new CxyException("9900", "模板加载异常", e);
        }
    }

    private static String invokeServiceHandle(CxyCloudAdapterConvertMetadata convertMetadata,
                                              String sourceReq) throws
            TemplateException, IOException {
        Map<String, Object> extMap = new HashMap<>();
        /*
          此时拥有的数据为，模板信息，原始req报文，ext贯穿对象
         */
        String targetRequest = converRequest(convertMetadata, sourceReq, extMap);
        /*
          此时拥有的数据为，模板信息，原始req报文，ext贯穿对象，req转换后报文
         */
        String sourceResponse = getResponse(convertMetadata, sourceReq, extMap, targetRequest);
        /*
          此时拥有的数据为，模板信息，原始req报文，ext贯穿对象，req转换后报文,原始resp报文
         */
        return converResponse(convertMetadata, sourceReq, extMap, targetRequest, sourceResponse);
    }

    private static String converResponse(CxyCloudAdapterConvertMetadata convertMetadata, String sourceReq,
                                         Map<String, Object> extMap, String targetRequest, String sourceResponse) throws
            IOException, TemplateException {
        HashMap<String, Object> respParam = new HashMap<>();
        respParam.put("sourceReq", MessageUtils.messageToMap(sourceReq));
        respParam.put("ext", extMap);
        respParam.put("targetReq", MessageUtils.messageToMap(targetRequest));
        respParam.put("resp", MessageUtils.messageToMap(sourceResponse));
        doBeforeRespProcessor(convertMetadata, sourceResponse, extMap);
        return CxyCloudTemplateUtils.convert(convertMetadata.getTempGroup(), convertMetadata.getRespTempName(), respParam);
    }

    private static void doBeforeRespProcessor(CxyCloudAdapterConvertMetadata convertMetadata,
                                              String sourceResponse, Map<String, Object> extMap) {
        List<CxyCloudAdapterConvertProcessor> processorList = convertMetadata.getProcessorList();
        if (processorList != null && processorList.size() > 0) {
            Map<String, Object> sourceRespMap = Collections.unmodifiableMap(MessageUtils.messageToMap(sourceResponse));
            for (CxyCloudAdapterConvertProcessor processor : processorList) {
                processor.beforeRespProcessor(sourceResponse, sourceRespMap, extMap);
            }
        }
    }

    private static String getResponse(CxyCloudAdapterConvertMetadata convertMetadata,
                                      String sourceReq,
                                      Map<String, Object> extMap, String targetRequest) throws IOException,
            TemplateException {
        String response;
        if (convertMetadata.isMock()) {
            HashMap<String, Object> mockParam = new HashMap<>();
            mockParam.put("sourceReq", MessageUtils.messageToMap(sourceReq));
            mockParam.put("ext", extMap);
            mockParam.put("req", MessageUtils.messageToMap(targetRequest));
            response = CxyCloudTemplateUtils.convert(convertMetadata.getTempGroup(), convertMetadata.getMockTempName(), mockParam);
        } else {
            CxyCloudAdapterService service = CxyCloudAdapterClientUtil.getAdapterService(convertMetadata.getOutServiceBeanName());
            response = service.doServiceImpl(convertMetadata.getOutCode(), targetRequest,extMap);
        }
        return response;
    }

    private static String converRequest(CxyCloudAdapterConvertMetadata convertMetadata,
                                        String sourceReq,
                                        Map<String, Object> extMap) throws
            TemplateException, IOException {
        Map<String, Object> requestParam = new HashMap<>();
        requestParam.put("req", MessageUtils.messageToMap(sourceReq));
        requestParam.put("ext", extMap);
        doBeforeReqProcessor(convertMetadata, sourceReq, extMap);
        return CxyCloudTemplateUtils.convert(convertMetadata.getTempGroup(), convertMetadata.getReqTempName(), requestParam);
    }

    private static void doBeforeReqProcessor(CxyCloudAdapterConvertMetadata gateWayServerMetadata, String sourceReq,
                                             Map<String, Object> extMap) {
        List<CxyCloudAdapterConvertProcessor> processorList = gateWayServerMetadata.getProcessorList();
        if (processorList != null && processorList.size() > 0) {
            Map<String, Object> sourceReqMap = Collections.unmodifiableMap(MessageUtils.messageToMap(sourceReq));
            for (CxyCloudAdapterConvertProcessor processor : processorList) {
                processor.beforeReqProcessor(sourceReq, sourceReqMap, extMap);
            }
        }
    }
}
